You didn't forget anything, it was just pure coincidence that I figured that out. Documentation just says:
take (
String item_name )

Takes away the specified item from the sentient.
I just noticed that other, similar, commands were documented to work on anything in the player inventory.
I suspected they meant the inventory as a whole, including ammo, and I tried the listinventory command
and noticed that ammo was kept seperate from weapons with keyname of the respective ammotype.
So I just tried it and it worked... for once 
As for the other problem. Yes, that's a big one. Up until now, the only way to make values persist through
restarts and mapchanges alike was by use of cvar. With reborn we can also write them to a physical file.
The problem of both methods is that the stored data has to be parsed at each restart/mapchange.
That being said, a cvar is more appealing since you don't have to confront yourself with the new
filesystem commands and elaborate parsing algorithms.
The disadvantage of using cvars is that their capacity is limited, in not just length (string size per cvar)
but also size (number of new cvars one can make before breaching the limit and crashing the game) and
scope (these cvars will not be written to config, they expire once the server shuts down).
This problem will be hopefully solved for good once I release the scripting framework. It's a problem that's
been bugging me for a long time. The framework will introduce SessionStorage (while the map stays the same)
and LocalStorage (until the server is shutdown) systems that can save all primitive types.
In the meantime, we'll stick with cvars. First you'll need a function that can split strings on a specific character.
This should do:
Code:
Split local.string local.spacer:
local.strSize = local.string.size
local.word = 1;
local.result[local.word] = "";
for (local.i = 0; local.i < local.strSize; local.i++) {
if (local.spacer == local.string[local.i]) {
if !(local.string[(local.i + 1)] == local.spacer) {
if(local.result[local.word] != "") {
local.word++;
local.result[local.word] = "";
}
}
continue;
}
local.result[local.word] += local.string[local.i];
}
end local.result;
The reason you need it, is because cvars can only store one string. This means your input
has to be formatted into a single string in such a way that we can easily translate that
string back into the original input later. This requires a 'compile' and a 'decompile' algorithm.
We'll start with compiling. Your input is the .swap property associated with all players currently
playing. The input will be your $player array but to differentiate between players we can't rely
on the client id number since it may change during a mapchange.
What doesn't change over a playing session on a server are their IP addresses. Too bad
there's a possibility of multiple players with the same IP on your server. However, even though
the player's name may change, we know it won't change during a mapchange (loading screen)
or a restart (too fast).
Now we have two values that allow us to pinpoint the same player no matter how many mapchanges or -restarts have occurred!
Let's start by compiling these three values. First, we need 2 global variables:
Code:
main:
level.valSep = "," //seperator character to seperate the values
level.entrSep = ";" //seperator character to seperate (player) entries
end;
Now for our compile thread:
Code:
Compile:
local.cvarStr = "";
for (local.i = 1; local.i <= $player.size; local.i++) {
local.player = $player[local.i];
// Catches all NILs
if (local.player.swap != "1") {
local.player.swap = "0"
}
/// Compilation phase.. no need to cast to string :)
// Add player's name value seperator player's ip value seperator player's property entry seperator
local.cvarStr += ((netname local.player) + (level.valSep) + (getip local.player) + (level.valSep) + (local.player.swap) + (level.entrSep));
}
// Save compiled string to cvar
setcvar "sessionSwapData" local.cvarStr;
end;
This should be run, ideally, during intermission. In other words right before a round or level ends.
I haven't experimented with the intermission event much, I hope it detects round restarts as well.
To present what I'm doing there more visually, I'm formatting a player's data like this:
name,ip,swap
eg:
unnamedsoldier,127.0.0.1,1
Each comma seperates each value. Values have fixed positions. Every such block is then terminated with a semicolon.
With this I can quickly differentiate between values and a block of values belonging to one player.
I guess this may cause problems if a player has a comma or a semicolon in his name... which is highly unusual but if it
bothers you, try using more exotic characters like these two escape sequences:
Code:
main:
level.valSep = "\t" //seperator character to seperate the values
level.entrSep = "\n" //seperator character to seperate (player) entries
end;
Both compile and decompile threads use these variables. So if there was a string saved from last round/level, we need to
decompile it with this:
Code:
Decompile:
// Break 'sessionSwapData' string into strings of the entries.
level.sessionSwapData = waitthread Split (getcvar("sessionSwapData")) level.entrSep;
// No longer needed;
setcvar "sessionSwapData" "";
// Array of strings isn't empty (this means the cvar "sessionSwapData" wasn't empty)
if (0 < level.sessionSwapData.size) {
// Save initial size (We're going to remove elements without reconcatenating
// the array later on to save time and resources).
level.sessionSwapDataSize = level.sessionSwapData.size;
// Split values as well and creat a two-dimensional array.
for (local.i = 1; local.i <= level.sessionSwapDataSize; local.i++) {
// Now split entry string into its 3 value strings. In our compile phase,
// each value had a fixed position. This is maintained. :)
level.sessionSwapData[local.i] = waitthread Split level.sessionSwapData[local.i] level.valSep;
}
}
end;
This script should be run, ideally, right after level waittill spawn.
Finally, register the connected event and make the connection script execute this thread:
Code:
GetSwapDataForClient local.player:
local.result = 0;
for (local.i = 1; local.i <= level.sessionSwapDataSize; local.i++) {
// Element is not inexistent and is an array which
// contains a valid amount of elements itself.
if (level.sessionSwapData[local.i].size == 3) {
if ((getip local.player) == local.sessionSwapData[local.i][2]) {
if ((netname local.player) == local.sessionSwapData[local.i][1]) {
// Player was found!
// He did not disconnect during mapchange...
local.player.swap = local.sessionSwapData[local.i][3];
// No need to keep this set of data anymore (frees memory and
// makes this algorithm run faster next time).
local.sessionSwapData[local.i] = NIL;
// exit
local.result = 1;
break;
}
}
}
}
end local.result;
This will find the correct swap value, if any, for the player and this thread will also return 1 if a value was found
and 0 if nothing was found.
I haven't actually tested it yet. But this is the general approach to take.